import org.jetbrains.annotations.NotNull;

import java.lang.reflect.*;
import java.util.Arrays;
import java.util.stream.Collectors;

public class GenericTest {

    public static void main(String[] args) throws Exception {
        Generic<String> genericWithString = new Generic<>();
        // 有一个类型变量
        assert genericWithString.getClass().getTypeParameters().length == 1;
        // 无法直接获取当前类的ParameterizedType，因为泛型
        assert genericWithString.getClass().getTypeParameters()[0].getClass().isAssignableFrom(TypeVariable.class);
        System.out.println("当前类的泛型信息：" + genericWithString.getClass().getTypeParameters()[0].getName());
        Field map = genericWithString.getClass().getField("map");
        Type type = map.getGenericType();
        System.out.println("map的泛型信息：" + type);
        Arrays.stream(genericWithString.getClass().getDeclaredMethods()).forEach(i -> {
            System.out.printf("""
                    方法名： %s
                    方法的泛型信息： %s
                    方法的参数类型： %s
                    方法的返回类型： %s
                    %n""", i.getName(), i.getGenericReturnType(), getGenericParameterType(i), i.getGenericReturnType());

        });
        // 创建匿名对象时，匿名对象可以保存当前类传递给父类的类型参数
        Generic generic1 = new Generic<Comparable<String>>() {
        };
        Type superclass = generic1.getClass().getGenericSuperclass();
        System.out.println("父类的泛型信息：" + superclass);
    }

    @NotNull
    private static String getGenericParameterType(Method method) {
      return   Arrays.stream(method.getGenericParameterTypes()).map(i -> {
            if (i instanceof TypeVariable<?>) {
                return i + " : " + ((TypeVariable<?>) i).getBounds()[0].getTypeName();
            } else {
                return i.getTypeName();
            }
        }).collect(Collectors.joining(", "));
    }

    static void getGenericInfo(Object o) {
        Class<?> aClass = o.getClass();
        TypeVariable<?>[] typeParameters = aClass.getTypeParameters();
        for (TypeVariable<?> typeVariable : typeParameters) {
            System.out.println(typeVariable.getName());
        }
    }

}
